package cn.com.libertymutual.wx.service.impl;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.beust.jcommander.internal.Maps;

import cn.com.libertymutual.core.http.HttpAndHttpsUtil;
import cn.com.libertymutual.core.redis.util.RedisUtils;
import cn.com.libertymutual.core.util.Constants;
import cn.com.libertymutual.core.util.DateUtil;
import cn.com.libertymutual.core.util.enums.CoreServiceEnum;
import cn.com.libertymutual.core.web.ServiceResult;
import cn.com.libertymutual.core.web.util.RequestUtils;
import cn.com.libertymutual.sp.bean.TbSpAccessToken;
import cn.com.libertymutual.sp.bean.TbSpApplicant;
import cn.com.libertymutual.sp.bean.TbSpKeywordWeChat;
import cn.com.libertymutual.sp.bean.TbSpOrder;
import cn.com.libertymutual.sp.bean.TbSpSaleLog;
import cn.com.libertymutual.sp.bean.TbSpUser;
import cn.com.libertymutual.sp.dao.AccessTokenDao;
import cn.com.libertymutual.sp.dao.ApplicantDao;
import cn.com.libertymutual.sp.dao.KeywordWeChatDao;
import cn.com.libertymutual.sp.dao.OrderDao;
import cn.com.libertymutual.sp.dao.SpSaleLogDao;
import cn.com.libertymutual.sp.dao.UserDao;
import cn.com.libertymutual.sp.dto.wechat.CommonUserInfo;
import cn.com.libertymutual.sp.dto.wechat.Message;
import cn.com.libertymutual.sp.dto.wechat.RuleReplyMsg;
import cn.com.libertymutual.sp.dto.wechat.TQueryRuleMsgRequestDto;
import cn.com.libertymutual.sp.dto.wechat.TQueryRuleMsgResponseDto;
import cn.com.libertymutual.sp.dto.wechat.UserGroupInfo;
import cn.com.libertymutual.sp.service.api.QueryPrdCodeService;
import cn.com.libertymutual.sys.bean.SysServiceInfo;
import cn.com.libertymutual.wx.common.MessageType;
import cn.com.libertymutual.wx.common.ResponseMessageParser;
import cn.com.libertymutual.wx.message.UserToken;
import cn.com.libertymutual.wx.message.WeChatUser;
import cn.com.libertymutual.wx.message.responsedto.ResponseBaseMessage;
import cn.com.libertymutual.wx.message.responsedto.TextMessage;
import cn.com.libertymutual.wx.service.WeChatService;
import cn.com.libertymutual.wx.util.WXUtil;

@Service
@RefreshScope // 刷新配置无需重启服务
public class WeChatServiceImpl implements WeChatService {
	private Logger logger = LoggerFactory.getLogger(getClass());

	/**微信公众号唯一ID*/
	@Value("${wechat.basic.appid}")
	public String APPID;

	/**微信公众号密钥*/
	@Value("${wechat.basic.appsecret}")
	public String APPSECRET;

	/**微信公众号校验key*/
	@Value("${wechat.basic.tokenkey}")
	public String TOKENKEY;

	// /**微信公众号自动回复默认信息*/
	// @Value("${wechat.basic.autoReturnDefaultMsg}")
	// public String AUTORETURNMSG;
	//
	// /**微信公众号用户消息关键词—产品列表*/
	// @Value("${wechat.basic.KEY_WORDS_PRODUCT_LIST}")
	// public String[] KEY_WORDS_PRODUCT_LIST;
	//
	// /**微信公众号用户消息关键词—家财险*/
	// @Value("${wechat.basic.KEY_WORDS_PRODUCT_TYPE_3105}")
	// public String[] KEY_WORDS_PRODUCT_TYPE_3105;
	//
	// /**微信公众号用户消息关键词—电子保单*/
	// @Value("${wechat.basic.KEY_WORDS_SERVICE_DZBD}")
	// public String[] KEY_WORDS_SERVICE_DZBD;
	//
	// /**微信公众号用户消息关键词—电子发票*/
	// @Value("${wechat.basic.KEY_WORDS_SERVICE_DZFP}")
	// public String[] KEY_WORDS_SERVICE_DZFP;
	//
	// /**微信公众号用户消息关键词—马上报案*/
	// @Value("${wechat.basic.KEY_WORDS_SERVICE_MSBA}")
	// public String[] KEY_WORDS_SERVICE_MSBA;
	//
	// /**微信公众号用户消息关键词—理赔查询*/
	// @Value("${wechat.basic.KEY_WORDS_SERVICE_LPCX}")
	// public String[] KEY_WORDS_SERVICE_LPCX;
	//
	// /**微信公众号用户消息关键词—验车码*/
	// @Value("${wechat.basic.KEY_WORDS_CAR_CODE}")
	// public String[] KEY_WORDS_CAR_CODE;

	@Autowired
	private UserDao userDao;
	@Autowired
	private OrderDao orderDao;
	@Autowired
	private ApplicantDao applicantDao;
	@Autowired
	private SpSaleLogDao spSaleLogDao;
	@Autowired
	private KeywordWeChatDao keywordWeChatDao;
	@Autowired
	private AccessTokenDao accessTokenDao;

	@Autowired
	private QueryPrdCodeService queryPrdCodeService;

	@Resource
	private RedisUtils redisUtils;

	@Resource(name = "restTemplate")
	private RestTemplate restTemplate;

	@Resource(name = "restTemplateHttps")
	private RestTemplate restTemplateHttps;

	@Resource
	private WXUtil wxUtil;

	@Override
	public String sort(String timestamp, String nonce) {
		String[] strArray = { TOKENKEY, timestamp, nonce };
		Arrays.sort(strArray);
		StringBuilder sb = new StringBuilder();
		for (String str : strArray) {
			sb.append(str);
		}
		return sb.toString();
	}

	@Override
	public String sha1(String str) {
		try {
			MessageDigest digest = MessageDigest.getInstance("SHA-1");
			digest.update(str.getBytes());
			byte messageDigest[] = digest.digest();
			// Create Hex String
			StringBuffer hexString = new StringBuffer();
			// 字节数组转换为 十六进制 数
			for (int i = 0; i < messageDigest.length; i++) {
				String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
				if (shaHex.length() < 2) {
					hexString.append(0);
				}
				hexString.append(shaHex);
			}
			return hexString.toString();

		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return "";
	}

	@Override
	public String getPublicAccessTokenCurrent(String title) {
		// 缓存的accessToken
		String accessToken = redisUtils.getString(WXUtil.ACCESSTOKEN);
		if (StringUtils.isNotBlank(accessToken)) {
			logger.info("redis获取当前全局accessToken[未过期]===>{}", accessToken);
			return accessToken;
		}

		TbSpSaleLog saleLog = new TbSpSaleLog();
		saleLog.setOperation(TbSpSaleLog.WECHAT_ACCESS_TOKEN);
		saleLog.setRequestTime(new Date());
		saleLog.setRequestData(title);
		saleLog.setMark("获取redis中的accesstoken为空");
		saleLog.setResponseData("待查数据库或重新获取");
		spSaleLogDao.save(saleLog);

		List<TbSpAccessToken> accessTokens = accessTokenDao.findAccessToken(Constants.ACCESS_TOKEN_TYPE_1, APPID);
		if (CollectionUtils.isNotEmpty(accessTokens)) {
			TbSpAccessToken tbSpAccessToken = accessTokens.get(0);

			accessToken = tbSpAccessToken.getPublicAccessToken();
			if (StringUtils.isNotBlank(accessToken)) {

				Date createDate = DateUtil.getDateByString(tbSpAccessToken.getCreateTime());
				long longtime = new Date().getTime() - createDate.getTime();

				// 在一个半小时内则token有效，默认有效2个小时
				if (longtime < WXUtil.REDIS_TIME_6000 * 1000) {

					// 以秒为单位存储accesstoken
					redisUtils.setStringWithExpireTime(WXUtil.ACCESSTOKEN, accessToken, WXUtil.REDIS_TIME_6000);

					return accessToken;
				} else {
					saleLog.setMark(saleLog.getMark() + "，DBMS中的accesstoken已过期");
				}
			} else {
				saleLog.setMark(saleLog.getMark() + "，获取DBMS中的accesstoken为空");
			}
		}

		// 获取新的AccessToken
		String requestUrl = WXUtil.GET_ACCESS_TOKEN_URL.replace("APPID", APPID).replace("APPSECRET", APPSECRET);
		JSONObject jsonObject = HttpAndHttpsUtil.httpsPost(requestUrl, HttpAndHttpsUtil.METHOD_GET, null);
		if (jsonObject == null) {

			String msg = "获取新的全局accessToken失败";
			saleLog.setMark(saleLog.getMark() + "，" + msg);
			saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
			saleLog.setResponseData(JSON.toJSONString(jsonObject));
			spSaleLogDao.save(saleLog);

			logger.info(msg);
			return "";
		}
		logger.info("获取新的全局access_token结果===>{}", JSON.toJSONString(jsonObject));

		accessToken = jsonObject.getString("access_token");// token
		if (StringUtils.isNotBlank(accessToken)) {

			// 以秒为单位存储accesstoken
			redisUtils.setStringWithExpireTime(WXUtil.ACCESSTOKEN, accessToken, WXUtil.REDIS_TIME_6000);

			Integer expires_in = jsonObject.getInteger("expires_in");// 时间

			String nowTime = DateUtil.getStringDate();
			// 创建
			if (CollectionUtils.isEmpty(accessTokens)) {
				TbSpAccessToken tbSpAccessToken = new TbSpAccessToken();
				tbSpAccessToken.setType(Constants.ACCESS_TOKEN_TYPE_1);
				tbSpAccessToken.setAppId(APPID);
				tbSpAccessToken.setSecret(APPSECRET);
				tbSpAccessToken.setTokenKey(TOKENKEY);

				tbSpAccessToken.setCreateTime(nowTime);
				tbSpAccessToken.setPublicAccessToken(accessToken);
				tbSpAccessToken.setExpiresIn(expires_in);
				tbSpAccessToken.setDayTimes(1);// 每天初始1
				// 第一次保存token
				accessTokenDao.save(tbSpAccessToken);
				saleLog.setMark(saleLog.getMark() + "，获取新的全局accessToken成功，第一次入库");
			} else {
				// 刷新数据库中的token
				TbSpAccessToken tbSpAccessToken = accessTokens.get(0);
				tbSpAccessToken.setCreateTime(nowTime);
				tbSpAccessToken.setPublicAccessToken(accessToken);
				tbSpAccessToken.setExpiresIn(expires_in);

				// 创建时间
				long createDate = DateUtil.getDateByString(tbSpAccessToken.getCreateTime()).getTime();
				// 今日凌晨
				long todayTime = DateUtil.getStartTime(0).getTime();
				// 上次创建时间大于当天凌晨时间，则表示改时间属于当天
				if (createDate - todayTime > 0) {
					tbSpAccessToken.setDayTimes(tbSpAccessToken.getDayTimes() + 1);
				} else {
					// 每天初始1
					tbSpAccessToken.setDayTimes(1);
				}
				// 刷新token
				accessTokenDao.save(tbSpAccessToken);
				saleLog.setMark(saleLog.getMark() + "，获取新的全局accessToken成功，数据库已刷新");
			}
			saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
			saleLog.setResponseData(JSON.toJSONString(jsonObject));
			spSaleLogDao.save(saleLog);

			return accessToken;
		}
		String errcode = jsonObject.getString("errcode");// 错误代码
		String errmsg = jsonObject.getString("errmsg");// 错误说明默认为错误信息
		switch (errcode) {
		case "-1":
			errmsg = "系统繁忙，此时请开发者稍候再试";
			break;
		case "0":
			errmsg = "请求成功";
			break;
		case "40001":
			errmsg = "AppSecret错误或者AppSecret不属于这个公众号，请开发者确认AppSecret的正确性";
			break;
		case "40002":
			errmsg = "请确保grant_type字段值为client_credential";
			break;
		case "40013":
			errmsg = "请确保grant_type字段值为client_credential";
			break;
		case "40164":
			errmsg = "调用接口的IP地址不在白名单中，请在接口IP白名单中进行设置";
		case "41001":
			errmsg = "accesstoken过期";
		case "45009":
			errmsg = "公众号接口访问次数到达了上限";
			break;
		case "60020":
			errmsg = "访问ip不在白名单之中";
			break;
		default:
			break;
		}

		String msg = "获取新的全局AccessToken[error]===>错误说明：" + errmsg;
		saleLog.setMark(saleLog.getMark() + "，" + msg);
		saleLog.setRequestData(requestUrl);
		saleLog.setResponseData(JSON.toJSONString(jsonObject));
		spSaleLogDao.save(saleLog);

		logger.info(msg);
		return "";
	}

	@Override
	public String getJSTicket() {
		// 默认读取缓存的ticket
		String ticket = redisUtils.getString(WXUtil.TICKET);
		if (StringUtils.isNotBlank(ticket)) {
			logger.info("获取Ticket[未过期]===>{}", ticket);
			return ticket;
		}

		TbSpSaleLog saleLog = new TbSpSaleLog();
		saleLog.setOperation(TbSpSaleLog.WECHAT_GET_TICKET);
		saleLog.setRequestTime(new Date());

		// 获取新的ticket
		String requestUrl = WXUtil.GET_JSSDK_TICKET_URL.replace("ACCESS_TOKEN", this.getPublicAccessTokenCurrent("获取新的ticket"));
		try {
			JSONObject jsonResult = HttpAndHttpsUtil.httpsPost(requestUrl, HttpAndHttpsUtil.METHOD_GET, null);
			// 判断token是否过期
			if (jsonResult == null) {

				String msg = "获取Ticket结果为空";
				saleLog.setRequestData(requestUrl);
				saleLog.setResponseData(msg);
				spSaleLogDao.save(saleLog);

				logger.info(msg);
				return "";
			}
			logger.info("获取新的ticket结果===>{}", JSON.toJSONString(jsonResult));

			// 如果请求成功
			if (StringUtils.isNotBlank(jsonResult.getString("ticket"))) {
				ticket = jsonResult.getString("ticket");
				redisUtils.setWithExpireTime(WXUtil.TICKET, ticket, 6000);
				return ticket;
			}
		} catch (Exception e) {
			String msg = "获取Ticket异常：" + e.toString();
			saleLog.setRequestData(requestUrl);
			saleLog.setResponseData(msg);
			spSaleLogDao.save(saleLog);

			logger.info(msg);
		}
		logger.info("获取Ticket失败");
		return "";
	}

	@Override
	public String getCode(String REDIRECT_URI, String type) {
		String code = String.format(WXUtil.GET_CODE_URL, APPID, REDIRECT_URI, type);
		logger.info("code：{}", code);
		return code;
	}

	@Override
	public UserToken getUserAccessToken(String code) {
		String requestUrl = String.format(WXUtil.GET_USER_ACCESS_TOKEN_URL, APPID, APPSECRET, code);
		JSONObject jsonObject = HttpAndHttpsUtil.httpsPost(requestUrl, HttpAndHttpsUtil.METHOD_GET, null);
		logger.info("获取getUserAccessToken结果===>{}", JSON.toJSONString(jsonObject));

		// 如果请求成功
		if (null != jsonObject) {
			if (StringUtils.isNotBlank(jsonObject.getString("openid")) && StringUtils.isNotBlank(jsonObject.getString("access_token"))) {
				UserToken userToken = new UserToken();
				userToken.setAccessToken(jsonObject.getString("access_token"));
				userToken.setOpenId(jsonObject.getString("openid"));
				logger.info("获取getUserAccessToken成功===>" + jsonObject);
				return userToken;
			} else {
				// 获取ticket失败
				logger.info("获取getUserAccessToken失败===>" + jsonObject);
			}
		}
		return null;
	}

	@Override
	public WeChatUser getUserInfo(String accessToken, String openId, String type) {
		if (StringUtils.isBlank(accessToken)) {
			logger.info("获取微信用户基本信息时accessToken为空");
			return null;
		}
		String requestUrl = null;
		if (WXUtil.SNSAPI_BASE.equals(type)) {
			// 静默授权URL
			requestUrl = String.format(WXUtil.POST_USER_INFO_URL_SILENT, accessToken, openId);// 全局accessToken
		} else if (WXUtil.SNSAPI_USERINFO.equals(type)) {
			// 网页授权URL
			requestUrl = String.format(WXUtil.GET_USER_INFO_URL_OAUTH, accessToken, openId);// userAccessToken
		}

		TbSpSaleLog saleLog = new TbSpSaleLog();
		saleLog.setOperation(TbSpSaleLog.WECHAT_OAUTH2);
		saleLog.setRequestTime(new Date());
		saleLog.setRequestData("accessToken=" + accessToken + "，openId=" + openId);
		saleLog.setMark("授权模式" + type);
		try {
			JSONObject jsonResult = HttpAndHttpsUtil.httpsPost(requestUrl, HttpAndHttpsUtil.METHOD_GET, null);
			if (jsonResult == null) {
				String msg = "获取微信用户基本信息结果为空";
				saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
				saleLog.setResponseData(msg);
				spSaleLogDao.save(saleLog);

				logger.info(msg);
				return null;
			}
			logger.info("获取微信用户基本信息结果===>{}", JSON.toJSONString(jsonResult));

			// 如果请求成功
			if (StringUtils.isNotBlank(jsonResult.getString("openid"))) {
				WeChatUser weChatUser = new WeChatUser();
				// 用户是否订阅该公众号标识，值为0时，代表此用户没有关注该公众号，拉取不到其余信息，只有openid和UnionID（在该公众号绑定到了微信开放平台账号时才有）。
				weChatUser.setSubscribe(jsonResult.getIntValue("subscribe"));
				// 用户的标识，对当前公众号唯一
				weChatUser.setOpenid(jsonResult.getString("openid"));
				// 用户的昵称
				weChatUser.setNickname(this.replaceEmoji(jsonResult.getString("nickname")));
				// 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知
				weChatUser.setSex(jsonResult.getIntValue("sex"));
				// 用户所在城市
				weChatUser.setCity(this.replaceEmoji(jsonResult.getString("city")));
				// 用户所在国家
				weChatUser.setCountry(this.replaceEmoji(jsonResult.getString("country")));
				// 用户所在省份
				weChatUser.setProvince(this.replaceEmoji(jsonResult.getString("province")));
				// 用户的语言，简体中文为zh_CN
				weChatUser.setLanguage(this.replaceEmoji(jsonResult.getString("language")));
				// 用户头像，最后一个数值代表正方形头像大小（有0、46、64、96、132数值可选，0代表640*640正方形头像），用户没有头像时该项为空。若用户更换头像，原有头像URL将失效。
				weChatUser.setHeadimgurl(this.replaceEmoji(jsonResult.getString("headimgurl")));
				// 用户关注时间，为时间戳。如果用户曾多次关注，则取最后关注时间
				weChatUser.setSubscribe_time(jsonResult.getLongValue("subscribe_time"));
				// 只有在用户将公众号绑定到微信开放平台帐号后，才会出现该字段。
				weChatUser.setUnionid(this.replaceEmoji(jsonResult.getString("unionid")));
				// 公众号运营者对粉丝的备注，公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
				weChatUser.setRemark(this.replaceEmoji(jsonResult.getString("remark")));
				// 用户所在的分组ID（暂时兼容用户分组旧接口）
				weChatUser.setGroupid(this.replaceEmoji(jsonResult.getString("groupid")));
				// 用户被打上的标签ID列表
				weChatUser.setTagid_list(this.replaceEmoji(jsonResult.getString("tagid_list")));

				saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
				saleLog.setResponseData("获取微信用户基本信息成功：" + JSON.toJSONString(jsonResult));
				spSaleLogDao.save(saleLog);

				return weChatUser;
			}
		} catch (Exception e) {
			String msg = "获取微信用户基本信息异常：" + e.toString();
			saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
			saleLog.setResponseData(msg);
			spSaleLogDao.save(saleLog);

			logger.info(msg);
		}

		String msg = "获取微信用户基本信息失败";
		saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
		saleLog.setResponseData(msg);
		spSaleLogDao.save(saleLog);

		logger.info(msg);
		return null;
	}

	@Override
	public String replaceEmoji(String str) {
		if (StringUtils.isNotBlank(str)) {
			str = str.replaceAll("[\ud800\udc00-\udbff\udfff\ud800-\udfff]", "");
		}
		return str;
	}

	@Override
	public String inputStream2String(InputStream in) throws Exception {
		if (in == null)
			return "";

		StringBuffer out = new StringBuffer();
		byte[] b = new byte[4096];
		for (int n; (n = in.read(b)) != -1;) {
			out.append(new String(b, 0, n, "UTF-8"));
		}
		return out.toString();
	}

	@Override
	@SuppressWarnings("unchecked") // 屏蔽某些编译时的警告信息(在强制类型转换的时候编译器会给出警告)
	public Map<String, String> parseXml(String inputXml) throws Exception {
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		// 读取输入流
		SAXReader reader = new SAXReader();
		reader.setEncoding("UTF-8");

		InputStream inputStream = new ByteArrayInputStream(inputXml.getBytes("UTF-8"));
		Document document = reader.read(inputStream);
		// 得到xml根元素
		Element root = document.getRootElement();
		// 得到根元素的所有子节点
		List<Element> elementList = root.elements();

		// 遍历所有子节点
		for (Element e : elementList)
			map.put(e.getName(), e.getText());

		// 释放资源
		inputStream.close();
		inputStream = null;

		return map;
	}

	/**
	 * Remarks: 根据用户操作和发送的消息内容匹配回复规则<br>
	 * Version：1.0<br>
	 * Author：AoYi<br>
	 * DateTime：2017年11月16日下午7:13:25<br>
	 * Project：liberty_sale_plat<br>
	 * 
	 * @param receiveMap
	 * @return
	 */
	public TQueryRuleMsgResponseDto getRule(Map<String, String> receiveMap) {
		Message message = new Message();
		message.setToUserName(receiveMap.get("ToUserName"));// gh_19bdee1b51ef
		message.setFromUserName(receiveMap.get("FromUserName"));// oGNKntw-WS1Jwi589dtxYDQCV1MA
		message.setContent(receiveMap.get("Content"));
		message.setMsgType(receiveMap.get("MsgType"));

		if (MessageType.REQ_MESSAGE_TYPE_EVENT.equals(message.getMsgType())) {
			// 事件类型
			message.setEvent(receiveMap.get("Event"));
		} else {
			// 消息类才有MsgId
			message.setMsgId(receiveMap.get("MsgId"));// 6488835809528904277
		}

		// 获取微信基本信息
		String accessToken = this.getPublicAccessTokenCurrent("静默获取微信用户基本信息");// 静默授权使用全局token
		WeChatUser weChatUser = this.getUserInfo(/* WXUtil.RETRYTIMES, */ accessToken, receiveMap.get("FromUserName"), WXUtil.SNSAPI_BASE);
		if (null != weChatUser) {
			CommonUserInfo userInfo = new CommonUserInfo();
			userInfo.setUserOpenId(weChatUser.getOpenid());
			userInfo.setSubscribeTime(new Date(weChatUser.getSubscribe_time()));
			userInfo.setNickname(weChatUser.getNickname());
			userInfo.setSex(weChatUser.getSex().compareTo(1) == 0 ? "男" : (weChatUser.getSex().compareTo(2) == 0 ? "女" : "未知"));
			userInfo.setCity(weChatUser.getCity());
			userInfo.setCountry(weChatUser.getCountry());
			userInfo.setProvince(weChatUser.getProvince());
			userInfo.setLanguage(weChatUser.getLanguage());
			userInfo.setHeadimgurl(weChatUser.getHeadimgurl());
			userInfo.setRemark(weChatUser.getRemark());

			UserGroupInfo groupInfo = new UserGroupInfo();
			groupInfo.setGroupId(weChatUser.getGroupid());
			userInfo.setGroup(groupInfo);

			message.setUser(userInfo);
		}

		@SuppressWarnings("rawtypes")
		Map map = (Map) redisUtils.get(Constants.SYS_SERVICE_INFO);
		SysServiceInfo sysServiceInfo = (SysServiceInfo) map.get(CoreServiceEnum.QUERY_RULE_MSG.getUrlKey());
		TQueryRuleMsgRequestDto msgRequestDto = new TQueryRuleMsgRequestDto();
		msgRequestDto.setPartnerAccountCode(sysServiceInfo.getUserName());
		msgRequestDto.setFlowId(DateUtil.dateFromat(new Date().getTime(), DateUtil.DATE_TIME_PATTERN4LANG));

		msgRequestDto.setMessage(message);

		HttpEntity<TQueryRuleMsgRequestDto> requestEntity = new HttpEntity<TQueryRuleMsgRequestDto>(msgRequestDto,
				RequestUtils.genEncryptHttpHeaders(sysServiceInfo.getUserName(), sysServiceInfo.getPassword()));
		TQueryRuleMsgResponseDto msgResponseDto = new TQueryRuleMsgResponseDto();
		msgResponseDto = restTemplate.postForObject(sysServiceInfo.getUrl(), requestEntity, TQueryRuleMsgResponseDto.class);

		logger.info("三方接口回复规则返回数据===>{}", JSON.toJSONString(msgResponseDto));
		return msgResponseDto;
	}

	@Override
	public String getUserGroupIdByOpenId(String openId) {
		String groupId = "";
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("openid", openId);
		String requestUrl = WXUtil.POST_USER_GROUP_ID_URL + "?access_token=" + this.getPublicAccessTokenCurrent("获取用户所在分组");

		TbSpSaleLog saleLog = new TbSpSaleLog();
		saleLog.setOperation(TbSpSaleLog.WECHAT_GET_GROUP_ID);
		saleLog.setRequestTime(new Date());
		saleLog.setRequestData("openId=" + openId);
		try {
			JSONObject jsonResult = postData(requestUrl, jsonObject.toString());
			if (jsonResult == null) {

				String msg = "获取用户所在分组结果为空";
				saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
				saleLog.setResponseData(msg);
				spSaleLogDao.save(saleLog);

				logger.info(msg);
				return groupId;
			}
			logger.info("获取用户所在分组结果===>{}", JSON.toJSONString(jsonResult));

			groupId = jsonResult.getString("groupid");
			if (StringUtils.isNotBlank(groupId)) {

				saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
				saleLog.setResponseData("获取用户所在分组成功：" + JSON.toJSONString(jsonResult));
				spSaleLogDao.save(saleLog);

				return jsonResult.getString("groupid");
			}
		} catch (Exception e) {
			String msg = "获取用户所在分组异常：" + e.toString();
			saleLog.setRequestData(saleLog.getRequestData() + "，" + requestUrl);
			saleLog.setResponseData(msg);
			spSaleLogDao.save(saleLog);

			logger.info(msg);
		}
		return groupId;
	}

	/**
	 * Remarks: 判断错误信息是否包含token过期提示<br>
	 * Version：1.0<br>
	 * Author：AoYi<br>
	 * DateTime：2017年11月27日下午3:24:58<br>
	 * Project：liberty_sale_plat<br>
	 * 
	 * @param jsonResult
	 * @return true = token过期
	 */
	// private boolean isInvalidToken(String jsonResult) {
	// String[] strings = { "access_token expired hint", "access_token is invalid or
	// not latest hint" };
	// for (String str : strings) {
	// if (jsonResult.contains(str)) {
	// return true;
	// }
	// }
	// return false;
	// }

	/**
	 * Remarks: 睡眠0.3秒<br>
	 * Version：1.0<br>
	 * Author：AoYi<br>
	 * DateTime：2017年11月27日上午11:17:55<br>
	 * Project：liberty_sale_plat<br>
	 */
	// private int sleepThreeSeconds(int retryErrMaxTimes) {
	// retryErrMaxTimes--;
	// try {
	// Thread.sleep(300);// 休眠0.3秒
	// } catch (InterruptedException e) {
	// e.printStackTrace();
	// }
	// return retryErrMaxTimes;
	// }

	@Override
	public boolean sendOderWeChatMsg(TbSpOrder or, String remarks) {
		// 投保人信息
		TbSpApplicant applicant = applicantDao.findByOrderNoAndType(or.getOrderNo(), "1");// 1=投保人
		logger.info("公众号开始推送消息===投保人==>{}", JSON.toJSONString(applicant));

		TbSpUser refereeUser = null;
		// 店主（分享人）
		if (StringUtils.isNotBlank(or.getRefereeId())) {
			refereeUser = userDao.findByUserCode(or.getRefereeId());
		}
		// 自己
		if (null == refereeUser && StringUtils.isNotBlank(or.getUserId())) {
			refereeUser = userDao.findByUserCode(or.getUserId());
		}
		logger.info("公众号开始推送消息===分享人==>{}", JSON.toJSONString(refereeUser));

		// 推荐人不为空，且推荐人已关注公众号，则发送消息
		if (null != refereeUser && "1".equals(refereeUser.getWxSubscribe())) {
			// 【投保人姓名】于【日期时间】通过您分享的链接投保了【产品名称计划名称】，保费【保费】元。
			String product = or.getProductName() + "-" + or.getPlanName();// 投保产品和计划
			String content = String.format(Constants.SMS_BY_PAY_MSG, applicant.getName(), DateUtil.getStringDate(), product, or.getAmount());
			if (StringUtils.isNotBlank(remarks)) {
				content += remarks;
			}
			boolean flag = this.sendTextMessageSingle(refereeUser.getWxOpenId(), MessageType.REQ_MESSAGE_TYPE_TEXT, content);
			// 日志
			TbSpSaleLog saleLog = new TbSpSaleLog();
			saleLog.setOperation(TbSpSaleLog.WECHAT_MSG);
			saleLog.setUserCode(refereeUser.getUserCode());
			saleLog.setMark(TbSpSaleLog.WECHAT_MSG);
			saleLog.setRequestTime(new Date());
			saleLog.setRequestData(
					"refereeUser：" + JSON.toJSONString(refereeUser) + "<br>,TbSpOrder：" + JSON.toJSONString(or) + "<br>,content：" + content);
			saleLog.setResponseData("【宝豆】推送结果：" + flag);
			spSaleLogDao.save(saleLog);
			return flag;
		}
		return false;
	}

	@Override
	public boolean sendTextMessageSingle(String toUserOpenId, String msgtype, String content) {
		if (StringUtils.isNotBlank(toUserOpenId)) {
			JSONObject jsonObj = new JSONObject();
			jsonObj.put("touser", toUserOpenId);
			jsonObj.put("msgtype", msgtype);
			JSONObject jsonContents = new JSONObject();
			jsonContents.put("content", content);
			jsonObj.put("text", jsonContents);
			return this.sendMessage(jsonObj.toJSONString());
		} else {
			logger.info("openID为空，不推送消息，本次内容：{}", content);
		}
		return false;
	}

	@Override
	public void sendNewsMessageSingle(String fromUserName, String title, String description, String url, String picurl) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("touser", fromUserName);
		jsonObject.put("msgtype", MessageType.RESP_MESSAGE_TYPE_NEWS);
		List<JSONObject> articles = new ArrayList<>();
		JSONObject article = new JSONObject();
		article.put("title", title);
		article.put("description", description);
		article.put("url", url);
		article.put("picurl", picurl);
		articles.add(article);// 单个图文信息
		JSONObject news = new JSONObject();
		news.put("articles", articles);// 图文列表
		jsonObject.put("news", news);
		this.sendMessage(jsonObject.toJSONString());
	}

	@Override
	public JSONObject postData(String url, String jsonStr) {
		try {
			// JSONObject result = HttpAndHttpsUtil.postJsonReturnJson(url, jsonStr,
			// "utf-8");
			HttpHeaders headers = new HttpHeaders();
			MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");// 防止中文乱码
			headers.setContentType(type);
			headers.add("Accept", MediaType.APPLICATION_JSON.toString());
			HttpEntity<String> httpEntity = new HttpEntity<String>(jsonStr, headers);

			JSONObject result = restTemplateHttps.postForObject(url, httpEntity, JSONObject.class);
			logger.info("result:{}", result);
			return result;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Map<String, String> keywordsReplyAndReturnXml(HttpServletRequest request, String fromUserName, String content, String returnXML,
			TextMessage textMessage) {

		Map<String, String> map = Maps.newHashMap();
		map.put("state", "false");
		map.put("type", "xml");
		map.put("xml", "");

		// 当前域名根路径
		String basePath = "https://" + request.getServerName();

		// 特殊字符测试发送消息是否可用
		if (content.contains("~!@#$%^&*()_+")) {
			returnXML = ResponseMessageParser.textMessageToXml(textMessage);

			map.put("state", "true");
			map.put("xml", returnXML);
			return map;
		}
		// 关键词查询
		List<TbSpKeywordWeChat> keywordWeChats = keywordWeChatDao.findAll();
		if (CollectionUtils.isEmpty(keywordWeChats)) {
			TbSpSaleLog saleLog = new TbSpSaleLog();// 日志
			saleLog.setOperation(TbSpSaleLog.WECHAT_KEYWORDS);
			saleLog.setMark("微信关键词查询为空");
			saleLog.setRequestTime(new Date());
			spSaleLogDao.save(saleLog);

			textMessage.setContent("微信关键词查询为空");
			returnXML = ResponseMessageParser.textMessageToXml(textMessage);

			map.put("state", "true");
			map.put("xml", returnXML);
			return map;
		}

		for (TbSpKeywordWeChat keyword : keywordWeChats) {

			if (keyword.getType().compareTo(Constants.WECHAT_KEYWORDS_TYPE0) == 0) {
				// ============================================公众号自动回复

			} else if (keyword.getType().compareTo(Constants.WECHAT_KEYWORDS_TYPE1) == 0) {
				// ============================================单个关键词回复

				// 验车码关键词回复
				if (Constants.KEY_WORDS_CAR_CODE.equalsIgnoreCase(keyword.getKeyName()) && content.trim().contains(keyword.getKeyWord())) {
					returnXML = queryPrdCodeService.executeQueryCheckCode(returnXML, textMessage);

					map.put("state", "true");
					map.put("xml", returnXML);
					return map;

				} else if ((Constants.KEY_WORDS_SERVICE_CXY.equalsIgnoreCase(keyword.getKeyName()) && content.trim().contains(keyword.getKeyWord()))
						|| (Constants.KEY_WORDS_SERVICE_JBAXTX.equalsIgnoreCase(keyword.getKeyName())
								&& content.trim().contains(keyword.getKeyWord()))) {
					// 出行易
					// 旧版安行天下
					String[] replyTexts = keyword.getReplyText().split(",");
					this.sendNewsMessageSingle(fromUserName, keyword.getKeyWord(), "", replyTexts[0], replyTexts[1]);

					map.put("type", "msg");
					return map;

				} else if (content.trim().equals(keyword.getKeyWord())) {
					// 精确匹配关键词
					textMessage.setContent(keyword.getReplyText());
					returnXML = ResponseMessageParser.textMessageToXml(textMessage);

					map.put("state", "true");
					map.put("xml", returnXML);
					return map;
				}

			} else if (keyword.getType().compareTo(Constants.WECHAT_KEYWORDS_TYPE2) == 0) {
				// ============================================多个关键词回复

				if (StringUtils.isBlank(keyword.getKeyWord())) {
					TbSpSaleLog saleLog = new TbSpSaleLog();// 日志
					saleLog.setOperation(TbSpSaleLog.WECHAT_KEYWORDS);
					saleLog.setMark("微信关键词内容为空");
					saleLog.setRequestTime(new Date());
					saleLog.setResponseData(JSON.toJSONString(keyword));
					spSaleLogDao.save(saleLog);
					continue;
				}
				// 关键词列表
				String[] keywords = keyword.getKeyWord().split(",");
				for (String str : keywords) {
					if (content.trim().equalsIgnoreCase(str)) {
						if (Constants.KEY_WORDS_PRODUCT_LIST.equals(keyword.getKeyName())// 产品列表
								|| Constants.KEY_WORDS_PRODUCT_TYPE_3105.equals(keyword.getKeyName()) // 家财险
								|| Constants.KEY_WORDS_SERVICE_DZBD.equals(keyword.getKeyName()) // 电子保单
								|| Constants.KEY_WORDS_SERVICE_DZFP.equals(keyword.getKeyName()) // 电子发票
								|| Constants.KEY_WORDS_SERVICE_MSBA.equals(keyword.getKeyName()) // 马上报案
								|| Constants.KEY_WORDS_SERVICE_LPCX.equals(keyword.getKeyName())) {//// 理赔查询
							String[] replyTexts = keyword.getReplyText().split(",");
							this.sendNewsMessageSingle(fromUserName, keyword.getKeyWord(), "", replyTexts[0], replyTexts[1]);

							map.put("type", "msg");
							return map;

						} else if (Constants.KEY_WORDS_DIGITAL_REPLY.equals(keyword.getKeyName())) {
							// 旅行险
							textMessage.setContent(keyword.getReplyText());
							returnXML = ResponseMessageParser.textMessageToXml(textMessage);

							map.put("state", "true");
							map.put("xml", returnXML);
							return map;
						} else {
							// 其他

						}
					}
				}
			}
		}

		return map;// 无需返回XML,继续判断三方接口的回复规则
	}

	@Override
	public String returnSingleMsg(String returnXML, Map<String, String> receiveMap, ResponseBaseMessage outputMessage, TextMessage textMessage,
			RuleReplyMsg ruleReplyMsg) {
		// 发送方帐号（open_id）
		String fromUserName = receiveMap.get("FromUserName");
		// 接收消息
		if (MessageType.REQ_MESSAGE_TYPE_TEXT.equals(ruleReplyMsg.getMsgType())) {

			String backText = ruleReplyMsg.getContent();
			// if (backText.indexOf("<") >= 0 && backText.lastIndexOf(">") >= 0) {
			// // 去掉a链接
			// backText = backText.substring(0, backText.indexOf("<")) +
			// backText.substring(backText.lastIndexOf(">") + 2);
			// }
			// 取代默认回复内容
			textMessage.setContent(backText);

			returnXML = ResponseMessageParser.textMessageToXml(textMessage);// 将回复内容转换成xml字符串
			logger.info("正在回复[文本]消息到微信用户[{}]，{}", fromUserName, textMessage.toString());

		} else if (MessageType.REQ_MESSAGE_TYPE_IMAGE.equals(ruleReplyMsg.getMsgType())) {

			this.sendMessage(ruleReplyMsg.getContent());
			logger.info("正在接收[图片]消息，来自微信用户[{}]，{}", fromUserName, textMessage.toString());

			// String mediaId = receiveMap.get("MediaId");
			// String picUrl = receiveMap.get("PicUrl");
			//
			// ImageMessage imageMessage = new ImageMessage(outputMessage);
			// imageMessage.setMediaId(mediaId);
			// imageMessage.setPicUrl(picUrl);
			//
			// returnXML = ResponseMessageParser.imageMessageToXml(imageMessage);//
			// 将回复内容转换成xml字符串
			// logger.info("正在接收[图片]消息，来自微信用户[{}]，{}", fromUserName,
			// imageMessage.toString());

		} else if (MessageType.REQ_MESSAGE_TYPE_LINK.equals(ruleReplyMsg.getMsgType())) {

			this.sendMessage(ruleReplyMsg.getContent());
			logger.info("正在回复[链接]消息到微信用户[{}]，{}", fromUserName, textMessage.toString());

			// NewsMessage newsMessage = new NewsMessage(outputMessage);
			// textMessage.setContent(backText + "<a href='https://s.libao.cn'>链接</a>");
			//
			// returnXML = ResponseMessageParser.newsMessageToXml(newsMessage);//
			// 将回复内容转换成xml字符串
			// logger.info("正在接收[链接]消息，来自微信用户[{}]，{}", fromUserName,
			// textMessage.toString());

		} else if (MessageType.REQ_MESSAGE_TYPE_LOCATION.equals(ruleReplyMsg.getMsgType())) {

			this.sendMessage(ruleReplyMsg.getContent());
			logger.info("正在回复[地理位置]消息到微信用户[{}]，{}", fromUserName, textMessage.toString());

			// String lx = receiveMap.get("Location_X");
			// String ly = receiveMap.get("Location_X");
			// textMessage.setContent(backText + "lx=" + lx + ",ly=" + ly);
			//
			// returnXML = ResponseMessageParser.textMessageToXml(textMessage);//
			// 将回复内容转换成xml字符串
			// logger.info("正在接收[地理位置]消息，来自微信用户[{}]，{}", fromUserName,
			// textMessage.toString());

		} else if (MessageType.RESP_MESSAGE_TYPE_MUSIC.equals(ruleReplyMsg.getMsgType())) {

			this.sendMessage(ruleReplyMsg.getContent());
			logger.info("正在回复[音乐]消息到微信用户[{}]，{}", fromUserName, textMessage.toString());

			// String mediaId = receiveMap.get("MediaId");
			//
			// MusicMessage musicMessage = new MusicMessage();
			// musicMessage.setToUserName(fromUserName);
			// musicMessage.setFromUserName(toUserName);
			// musicMessage.setCreateTime(new Date().getTime());
			// musicMessage.setMediaId(mediaId);
			//
			// returnXML = ResponseMessageParser.musicMessageToXml(musicMessage);//
			// 将回复内容转换成xml字符串
			// logger.info("正在接收[音乐]消息，来自微信用户[{}]，{}", fromUserName,
			// musicMessage.toString());

		} else if (MessageType.REQ_MESSAGE_TYPE_VOICE.equals(ruleReplyMsg.getMsgType())) {

			this.sendMessage(ruleReplyMsg.getContent());
			logger.info("正在回复[语音]消息到微信用户[{}]，{}", fromUserName, textMessage.toString());

			// String mediaId = receiveMap.get("MediaId");
			// String format = receiveMap.get("Format");
			//
			// VoiceMessage voiceMessage = new VoiceMessage(outputMessage);
			// voiceMessage.setMediaId(mediaId);
			// voiceMessage.setFormat(format);
			//
			// returnXML = ResponseMessageParser.voiceMessageToXml(voiceMessage);//
			// 将回复内容转换成xml字符串
			// logger.info("正在接收[语音]消息，来自微信用户[{}]，{}", fromUserName,
			// voiceMessage.toString());

		} else if (MessageType.REQ_MESSAGE_TYPE_VIDEO.equals(ruleReplyMsg.getMsgType())) {

			this.sendMessage(ruleReplyMsg.getContent());
			logger.info("正在回复[视频]消息到微信用户[{}]，{}", fromUserName, textMessage.toString());

			// String mediaId = receiveMap.get("MediaId");
			// String thumbMediaId = receiveMap.get("ThumbMediaId");
			//
			// VideoMessage videoMessage = new VideoMessage(outputMessage);
			// videoMessage.setMediaId(mediaId);
			// videoMessage.setThumbMediaId(thumbMediaId);
			//
			// returnXML = ResponseMessageParser.videoMessageToXml(videoMessage);//
			// 将回复内容转换成xml字符串
			// logger.info("正在接收[视频]消息，来自微信用户[{}]，{}", fromUserName,
			// videoMessage.toString());

		} else {

			this.sendMessage(ruleReplyMsg.getContent());
			logger.info("正在回复[其他]消息到微信用户[{}]，{}", fromUserName, textMessage.toString());

			// // 其他消息类型——默认回复
			// textMessage.setContent("感谢关注利宝保险！");
			// returnXML = ResponseMessageParser.textMessageToXml(textMessage);//
			// 将回复内容转换成xml字符串
			// logger.info("正在接收[其他]消息，来自微信用户[{}]，{}", fromUserName,
			// textMessage.toString());
		}

		return returnXML;
	}

	@Override
	public boolean sendMessage(String jsonStr) {
		String url = WXUtil.SEND_MESSAGE_URL + "?access_token=" + this.getPublicAccessTokenCurrent("微信发送消息");
		JSONObject jsonResult = this.postData(url, jsonStr);
		if (jsonResult == null) {
			return false;
		}
		if ("0".equals(jsonResult.getString("errcode")) || "ok".equals(jsonResult.getString("errmsg"))) {
			return true;
		} else {
			logger.info("发送信息[error]===>返回信息===>{}", jsonResult);
		}
		return false;
	}

	/**
	 * 判断是否是微信号(微信号是否符合规则)
	 * 
	 * @param weAccount
	 *            微信号
	 * @return 验证是否成功
	 */
	public boolean isWeAccount(String weAccount) {
		// 去掉前后空格
		return weAccount.matches("^[a-zA-Z]([a-zA-Z0-9]|[_-]){5,19}$");
	}

	@Override
	public boolean copyWeChatToBbean(WeChatUser weChatUser, TbSpUser user, boolean isMust) {
		boolean flag = false;
		if (null == weChatUser) {
			return flag;
		}

		// logger.info("最新微信信息===>weChatUser：{}", JSON.toJSONString(weChatUser));
		// logger.info("要被覆盖的用户===>user：{}", JSON.toJSONString(user));

		// openId
		if (isMust) {
			user.setWxOpenId(weChatUser.getOpenid());
			flag = true;
		} else {
			if (StringUtils.isBlank(user.getWxOpenId()) || !user.getWxOpenId().equals(weChatUser.getOpenid())) {
				user.setWxOpenId(weChatUser.getOpenid());
				flag = true;
			}
		}
		// 昵称
		if (isMust) {
			user.setNickName(weChatUser.getNickname());
			flag = true;
		} else {
			if (StringUtils.isBlank(user.getNickName()) || !user.getNickName().equals(weChatUser.getNickname())) {
				user.setNickName(weChatUser.getNickname());
				flag = true;
			}
		}
		// 头像地址
		if (isMust) {
			user.setHeadUrl(weChatUser.getHeadimgurl());
			flag = true;
		} else {
			if (StringUtils.isBlank(user.getHeadUrl()) || !user.getHeadUrl().equals(weChatUser.getHeadimgurl())) {
				user.setHeadUrl(weChatUser.getHeadimgurl());
				flag = true;
			}
		}
		// 用户是否订阅该公众号标识，值为0时，代表此用户没有关注该公众号，拉取不到其余信息。
		if (StringUtils.isBlank(user.getWxSubscribe()) || weChatUser.getSubscribe() > 0) {
			user.setWxSubscribe(weChatUser.getSubscribe().toString());
			flag = true;
		}

		// 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知
		if (StringUtils.isBlank(user.getWxSex()) || weChatUser.getSex() >= 0) {
			user.setWxSex(weChatUser.getSex().toString());
			flag = true;
		}
		// 用户所在城市
		if (StringUtils.isBlank(user.getWxCity()) || !user.getWxCity().equals(weChatUser.getCity())) {
			user.setWxCity(weChatUser.getCity());
			flag = true;
		}
		// 用户所在省份
		if (StringUtils.isBlank(user.getWxProvince()) || !user.getWxProvince().equals(weChatUser.getProvince())) {
			user.setWxProvince(weChatUser.getProvince());
			flag = true;
		}
		// 用户所在国家
		if (StringUtils.isBlank(user.getWxCountry()) || !user.getWxCountry().equals(weChatUser.getCountry())) {
			user.setWxCountry(weChatUser.getCountry());
			flag = true;
		}
		// 用户的语言，简体中文为zh_CN
		if (StringUtils.isBlank(user.getWxLanguage()) || !user.getWxLanguage().equals(weChatUser.getLanguage())) {
			user.setWxLanguage(weChatUser.getLanguage());
			flag = true;
		}
		// 用户的性别，值为1时是男性，值为2时是女性，值为0时是未知
		if (null == user.getWxSubscribeTime() || StringUtils.isBlank(user.getWxSubscribeTime().toString()) || weChatUser.getSubscribe_time() >= 0) {
			user.setWxSubscribeTime(new Timestamp(weChatUser.getSubscribe_time()));
			flag = true;
		}
		// 只有在用户将公众号绑定到微信开放平台帐号后，才会出现该字段。
		if (StringUtils.isBlank(user.getWxUnionid()) || !user.getWxUnionid().equals(weChatUser.getUnionid())) {
			user.setWxUnionid(weChatUser.getUnionid());
			flag = true;
		}
		// 公众号运营者对粉丝的备注，公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
		if (StringUtils.isBlank(user.getWxRemark()) || !user.getWxRemark().equals(weChatUser.getRemark())) {
			user.setWxRemark(weChatUser.getRemark());
			flag = true;
		}
		// 用户所在的分组ID（兼容旧的用户分组接口）
		if (StringUtils.isBlank(user.getWxGroupid()) || !user.getWxGroupid().equals(weChatUser.getGroupid())) {
			user.setWxGroupid(weChatUser.getGroupid());
			flag = true;
		}
		// 用户被打上的标签ID列表
		if (StringUtils.isBlank(user.getWxTagidList()) || !user.getWxTagidList().equals(weChatUser.getTagid_list())) {
			user.setWxTagidList(weChatUser.getTagid_list());
			flag = true;
		}
		// logger.info("已覆盖的用户===>user：{}", JSON.toJSONString(user));
		return flag;
	}

	@Override
	public ServiceResult reissue(String userCode, String type, String policyNo, String activityName, Integer beans, Integer times) {
		ServiceResult sr = new ServiceResult();

		TbSpUser user = userDao.findByUserCode(userCode);
		if (null == user) {
			sr.setAppFail("用户不存在");
			return sr;
		}
		// 日志
		TbSpSaleLog saleLog = new TbSpSaleLog();
		saleLog.setOperation(TbSpSaleLog.WECHAT_MSG);
		saleLog.setUserCode(user.getUserCode());
		saleLog.setMark(TbSpSaleLog.WECHAT_MSG);
		saleLog.setRequestTime(new Date());
		saleLog.setRequestData("userCode：" + userCode + "type：" + type + "policyNo：" + policyNo + "activityName：" + activityName + "beans：" + beans
				+ "times：" + times);

		if (Constants.ISSUE_ACTIVITY.equals(type)) {// 1=出单-规则
			List<TbSpOrder> orders = orderDao.findByPolicyNo(policyNo);
			if (CollectionUtils.isNotEmpty(orders)) {
				if (orders.size() > 1) {
					sr.setAppFail("保单号存在多条记录！");
					return sr;
				}
				TbSpOrder order = orders.get(0);
				// 投保人信息
				TbSpApplicant applicant = applicantDao.findByOrderNoAndType(order.getOrderNo(), "1");// 1=投保人
				logger.info("公众号开始推送消息===投保人==>{}", JSON.toJSONString(applicant));

				String product = order.getProductName() + "-" + order.getPlanName();// 投保产品和计划

				String content = String.format(Constants.SMS_BY_PAY_MSG, applicant.getName(), DateUtil.getStringDate(), product, order.getAmount());

				content += beans > 0 ? String.format(Constants.SMS_BY_PAY_BEANS, beans) : "";
				boolean flag = this.sendTextMessageSingle(user.getWxOpenId(), MessageType.REQ_MESSAGE_TYPE_TEXT, content);

				saleLog.setResponseData("【手动】推送结果：" + flag);
				spSaleLogDao.save(saleLog);

				sr.setSuccess();
				sr.setResult("推送成功");
				return sr;
			} else {
				sr.setAppFail("未查询到该订单！");
				return sr;
			}
		}
		if (Constants.EXTENSION_ACTIVITY.equals(type)) {// 2=出单-活动
			if (StringUtils.isNotBlank(activityName) && null != beans) {

				String content = Constants.SMS_BY_ACTIVITY_BEANS_PREFIX + String.format(Constants.SMS_BY_ACTIVITY_BEANS_SUFFIX, activityName, beans);
				content += "。";
				boolean flag = this.sendTextMessageSingle(user.getWxOpenId(), MessageType.REQ_MESSAGE_TYPE_TEXT, content);

				saleLog.setResponseData("【手动】推送结果：" + flag);
				spSaleLogDao.save(saleLog);

				sr.setSuccess();
				sr.setResult("推送成功");
				return sr;
			}
		}
		if (Constants.LUCK_DRAW_ACTIVITY.equals(type)) {// 3=抽奖-活动
			if (StringUtils.isNotBlank(activityName) && null != times) {

				String content = String.format(Constants.SMS_BY_ACTIVITY_TIMES, times, activityName);
				boolean flag = this.sendTextMessageSingle(user.getWxOpenId(), MessageType.REQ_MESSAGE_TYPE_TEXT, content);

				saleLog.setResponseData("【手动】推送结果：" + flag);
				spSaleLogDao.save(saleLog);

				sr.setSuccess();
				sr.setResult("推送成功");
				return sr;
			}
		}
		return sr;
	}
}
